﻿/*  -------------------------------------------------
    This file is part of the SchoolTube Live Platform
    Copyright © 2009 SchoolTube, LLC
    
    Licensed under the GNU General Public License v3
    http://www.gnu.org/licenses/gpl.html
    
    http://code.google.com/p/schooltubelive/
    ------------------------------------------------- */

import com.schooltube.audio.microphone.ActivityMonitor;

import flash.events.MouseEvent;

import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.effects.Resize;

private var appVer:String	= "0.1.5";
private var appURL:String	= "rtmp://fmspush.schooltube.com/stlive/default";

private var camera:Camera;
private var mic:Microphone;
private var nc:NetConnection;
private var nsOut:NetStream;
private var nsIn:NetStream;
private var cameraList:Camera;
private var rs:Resize;
private var ncStats:SharedObject;
private var statsInt:uint;
private var videoIn:Video;
private var cameraStatus:String;
private var updateDelay:uint;
private var micActivity:ActivityMonitor;

private static const msgConfig:String = "Sorry, but a camera was not detected.  Please connect first";

private function checkConnect() : void {
	if (txtUsername.text == "") {
		Alert.show("No username", "Error");
	} else if (txtPassword.text == "") {
		Alert.show("No password", "Error");
	} else {
		doConnect();
	}
}

private function doConnect() : void {
	nc = new NetConnection();
	
	nc.client = this;
	
	nc.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
	
	nc.proxyType = "HTTP";
	nc.connect(appURL, false, txtUsername.text, txtPassword.text);
}

public function close():void {}
public function onBWDone():void {}

private function netStatus(event:NetStatusEvent) : void {
	var info:Object = event.info;
	
    switch(info.code) 
    {
    	
    	case "NetConnection.Connect.Success":
    		
    		if ( doPublishStream() ) {
   				showApp();
				statsInt = setInterval(updateClientStats, 1000);
				
    			ncStats = SharedObject.getRemote('appSO/' + txtUsername.text.toLowerCase(), nc.uri, true);
    			ncStats.connect(nc);
    			ncStats.addEventListener(SyncEvent.SYNC, ncStatsSyncHandler);
    			
				if (videoIn) {
					videoIn.clear();
					nsIn.close();
				}
    			
    			nsIn = new NetStream(nc);
    			var nsClient:Object = {};
    			nsClient.onMetaData = ns_onMetaData;
				nsIn.client = nsClient;
				
				var sndTransform:SoundTransform = new SoundTransform(0);
				
				nsIn.soundTransform = sndTransform;
				
				var videoIn:Video = new Video();
				videoIn.smoothing = true;
				videoIn.attachNetStream(nsIn);
				nsIn.play(txtUsername.text.toLowerCase());
				videoIn.width = 318;
				videoIn.height = 238;
				localVideoUic.addChild(videoIn);
				
				txtEmbedCode.text = '<object width="420" height="375"><param name="movie" value="http://www.schooltube.com/l/'
    							+ txtUsername.text.toLowerCase() + '" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" />'
    							+ '<embed src="http://www.schooltube.com/l/'
    							+ txtUsername.text.toLowerCase() + '" type="application/x-shockwave-flash" allowFullScreen="true" allowscriptaccess="always" width="420" height="375"></embed></object>';
    							
    			txtEmbedCode.addEventListener(MouseEvent.CLICK, copyEmbedCode);
				
				nc.call('addViewCount', null, txtUsername.text);
   			} else {
   				hideApp();
   				if (camera) {
   					Alert.show('Internal error occured.', 'Error');
   				}
   			}
			break;
			
		case "NetConnection.Connect.Rejected":
		
    		Alert.show("Login Failed", "Error");
    		hideApp();
    		if (statsInt) {
    			clearInterval(statsInt);
    		}
    		break;
    		
    	case "NetConnection.Connect.Failed":

    		nsIn.close();
    		hideApp();
    		if (statsInt) {
    			clearInterval(statsInt);
    		}

    		break;
    	
    	case "NetConnection.Connect.Closed":
    		
    		nsIn.close();
    		localVideoUic.removeChildAt(0);
    		hideApp();
    		if (statsInt) {
    			clearInterval(statsInt);
    		}

    		break;
    }
}

private function ns_onMetaData(item:Object):void {}

private function ncStatsSyncHandler (event:SyncEvent) : void {
	if (ncStats.data.totalViewerCount) {
		lblLiveViewers.text = ncStats.data.totalViewerCount.toString();
	}
	if (ncStats.data.totalConnectCount) {
		lblConnections.text = ncStats.data.totalConnectCount.toString();
	}
	if (ncStats.data.streamName) {
		txtBroadcastName.text = ncStats.data.streamName.toString();
	}
}

private function updateClientStats ():void {
	var re:Responder = new Responder(res);
	function res(info:Object):void {
		lblBytesIn.text = Math.round(info['bytes_out'] / 1024).toString();
		lblBytesOut.text = Math.round(info['bytes_in'] / 1024).toString();
	}
	nc.call("getStats", re);
}

private function handlerCameraStatus( event:StatusEvent ) : void {
   	var cameraStatus:String = event.code;
   	if (event.code == "Camera.Muted") {
   		Alert.show('You must allow access to your camera to use this program.', 'Error', Alert.OK, null, showPrivacyPanel);
   	}
   	trace( event.code );
}

private function showPrivacyPanel(eventObject:Object):void {
	Security.showSettings(SecurityPanel.PRIVACY);
}

private function doPublishStream():Boolean {

	nsOut = new NetStream(nc);
	var nsClient:Object = new Object();
	nsClient.onMetaData = onMetaData;
	nsOut.client = nsClient;

	if (camera == null) {
		camera = Camera.getCamera();
	}
	
	if ( camera == null ) {
		if ( Camera.names.length > 0 ) {
			Alert.show( 'The default camera is in use by another application.', 'Error' );
		} else {
			Alert.show( 'There is no camera installed on your system.', 'Error' );
		}
	} else {
		camera.addEventListener( StatusEvent.STATUS, handlerCameraStatus );
		nsOut.attachCamera(camera); 
	}
	
	if (mic == null) {
		mic = Microphone.getMicrophone();
		mic.setLoopBack(false);
		mic.setUseEchoSuppression(true);
		micActivity = new ActivityMonitor(10, 240, [0x009900, 0xFFCC00, 0xCC0000]);
		uicMicActivity.addChild(micActivity);
	}
	
	if ( mic == null )
	{
		
		if ( Microphone.names.length > 0 ) {
			Alert.show('The default microphone is in use by another application.', 'Error');
		} else {	
			Alert.show('There is no microphone installed on your system.', 'Error');
		}
	} else {
		
		var micList:ArrayCollection = new ArrayCollection();
		for (var x:int=0;x<Microphone.names.length;x++){
			var obj:Object = new Object();
			obj.data = x;
			obj.label = Microphone.names[x];
			micList.addItem(obj);
		}
		cbMicSource.dataProvider = micList;
		cbMicSource.selectedIndex = mic.index;
		
		nsOut.attachAudio(mic);
	}

	if ( camera ) { 
		camera.setMode(320, 240, 29);  
		camera.setQuality(0, sldImageQuality.value * 30); 				
		nsOut.addEventListener(NetStatusEvent.NET_STATUS, handleNetStreamStatus);
		nsOut.publish(txtUsername.text.toLowerCase());
		
		var cameraList:ArrayCollection = new ArrayCollection();
		for (var c:int=0;c<Camera.names.length;c++){
			var cobj:Object = new Object();
			cobj.data = c;
			cobj.label = Camera.names[c];
			cameraList.addItem(cobj);
		}
		cbCameraSource.dataProvider = cameraList;
		cbCameraSource.selectedIndex = camera.index;
		
		localVideo.attachCamera(camera);
		return true;
	} else {
		nsOut.close();

		nsOut = null;
		return false;
	}
}

private function onMetaData(item:Object):void {}

private function handleNetStreamStatus(event:NetStatusEvent):void {
	var myMetaData:Object = new Object();
	myMetaData.author = txtUsername.text;
	myMetaData.width = 300;
	myMetaData.height = 240;
	nsOut.send("@setDataFrame", "onMetaData", myMetaData);
}

private function stopBroadcast():void {
	nc.close();
}

private function initApp() : void {
	
	var menuVersion:ContextMenuItem = new ContextMenuItem("SchoolTube Live Broadcaster - v" + appVer);
	menuVersion.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handleMenuClick);
	
	var menuCopyright:ContextMenuItem = new ContextMenuItem("Copyright © 2009 SchoolTube, LLC");
	menuCopyright.separatorBefore = true;
	menuCopyright.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handleMenuClick);
	
	var customContextMenu:ContextMenu = new ContextMenu();
	customContextMenu.hideBuiltInItems();
	customContextMenu.customItems.push(menuVersion, menuCopyright);
	
	mx.core.Application.application.contextMenu = customContextMenu;
	
	Security.exactSettings = false;
	hideApp();
	txtUsername.setFocus();
}

private function handleMenuClick(event:ContextMenuEvent):void {
	gotoURL("http://www.schooltube.com/live");
}

private function showApp():void {
	cvsMain.width = 670;
	cvsMain.height = 520;
	cvsBroadcasting.visible = true;
	cvsBottom.visible = true;
	cvsLocalVideo.visible = true;
	cvsLogin.visible = false;
}

private function hideApp():void {
	cvsMain.width = 320;
	cvsMain.height = 264;
	lblCodeCopied.visible = false;
	cvsBroadcasting.visible = false;
	cvsBottom.visible = false;
	cvsLocalVideo.visible = false;
	cvsLogin.visible = true;
}

private function gotoURL(URL:String, Target:String = '_blank'):void {
	var URLReq:URLRequest = new URLRequest(URL);
	navigateToURL(URLReq, Target);
}

private function formatImageQuality(item:Number):String {
	var retString:String = new String();
	switch (item) {
		case 1:
			retString = "Low";
		break;
		case 2:
			retString = "Medium";
		break;
		case 3:
			retString = "High";
		break;
	}
	
	return retString;
}

private function changeQuality():void {
	if (camera) {
		camera.setQuality(0, sldImageQuality.value * 30);
	}
}

private function changeVolume():void {
	if (mic) {
		mic.gain = sldMicVolume.value;
	}
}

private function updateBroadcastName():void {
	if (nc) {
		clearTimeout(updateDelay);
		updateDelay = setTimeout(function():void{nc.call("setStreamName", null, txtUsername.text, txtBroadcastName.text);}, 1000);
	}
	
}

private function changeMicSource(event:Event):void {
	if (mic && nsOut) {
		mic = Microphone.getMicrophone(event.currentTarget.selectedItem.data);
		micActivity.updateMicSelection(event.currentTarget.selectedItem.data);
		nsOut.attachAudio(mic);
	}
}

private function changeCameraSource(event:Event):void {
	if (camera && nsOut) {
		camera = Camera.getCamera(event.currentTarget.selectedItem.data);
		if (camera) {
			nsOut.attachCamera(camera);
			localVideo.attachCamera(camera);
		}
	}
}

private function copyEmbedCode(e:MouseEvent):void {
	txtEmbedCode.setSelection(0, txtEmbedCode.text.length);
	System.setClipboard(txtEmbedCode.text);
	lblFeedback();
}

private function lblFeedback():void {
	lblCodeCopied.visible = true;
	setTimeout(function():void{lblCodeCopied.visible = false;}, 5000);
}